import sys
import numpy as np
import threading,time,cv2,json,os
from ultralytics import YOLO
from threading import Thread
from PIL import Image, ImageDraw, ImageFont
from PyQt5 import QtGui,QtCore,QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QFileDialog, QListWidgetItem, QListView, QMessageBox
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from test import QMainWindow_new

class MplCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111, projection='3d')
        self.axes.set_xlim(0, 100)
        self.axes.set_ylim(-50,50)
        self.axes.set_zlim(-50,50)
        self.axes.invert_yaxis()
        super(MplCanvas, self).__init__(fig)

class myPredict(QObject):
    singal = pyqtSignal(int)

    font1 = QtGui.QFont("Adobe 黑体 Std R")
    font1.setPixelSize(32)
    font2 = QtGui.QFont("Adobe 黑体 Std R")
    font2.setPixelSize(24)
    font3 = QtGui.QFont("Adobe 黑体 Std R")
    font3.setPixelSize(16)

    target_list = []
    results_list = []

    di = [(640, 360), (1280, 720), (1920, 1080)]
    size_dic = {0: "小", 1: "中", 2: "大"}
    dil = 1
    Tshow = False
    N, X, Y, Z = [''], [0], [0], [0]

    def __init__(self):
        super(myPredict, self).__init__()
        with open("runin_predict.json", encoding="utf-8") as file:
            self.D = json.load(file)
        self.dil = self.D["show_size"]
        self.event=threading.Event()
        self.event.set()
        self.run=True
        self.create_window()

    def show_chinese(self, img, text, pos ,fil):
        img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        font = ImageFont.truetype(font='msyh.ttc', size=self.D["font_size"])
        draw = ImageDraw.Draw(img_pil)
        draw.text(pos, text, font=font, fill=fil)  # PIL中RGB=(255,0,0)表示红色
        img_cv = np.array(img_pil)  # PIL图片转换为numpy
        img = cv2.cvtColor(img_cv, cv2.COLOR_RGB2BGR)  # PIL格式转换为OpenCV的BGR格式
        return img

    def mat_to_qimage(self, mat):
        rgb_image = cv2.cvtColor(mat, cv2.COLOR_BGR2RGB)
        h, w, ch = rgb_image.shape
        bytes_per_line = ch * w
        img_qt = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
        return img_qt

    def create_window(self):
        # 主界面
        self.mainWindow = QMainWindow_new()
        self.mWw = 590
        self.mWh = 880
        self.mainWindow.resize(self.mWw, self.mWh)
        self.mainWindow.move(250, 300)
        self.mainWindow.setFixedSize(self.mWw, self.mWh)
        # self.window.setWindowIcon(QIcon(r'ui\image\title.ico'))

        label_backdrop = QLabel(self.mainWindow)
        label_backdrop.resize(1050, self.mWh)
        label_backdrop.setStyleSheet("background-color: rgb(240, 250, 250);")

        self.label_main_title = QLabel(self.mainWindow)
        self.label_main_title.resize(self.mWw, 50)
        self.label_main_title.setText("    检测目标")
        self.label_main_title.setFont(QtGui.QFont("Adobe 黑体 Std R", 16))
        self.label_main_title.setStyleSheet("background-color: rgb(50, 200, 200);")

        label_T = QLabel(self.mainWindow)
        label_T.resize(40, 40)
        label_T.move(5, 5)
        label_T.setPixmap(QPixmap(r"ui\label.jpg").scaled(label_T.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))

        self.button_main_close = QPushButton(self.mainWindow)
        self.button_main_close.setStyleSheet("QPushButton {border: none;}")
        self.button_main_close.setIcon(QIcon(r"ui\close.png"))
        self.button_main_close.resize(50, 50)
        self.button_main_close.move(self.mWw - 50, 0)
        self.button_main_close.clicked.connect(self.mainWindow.close)

        self.button_main_min = QPushButton(self.mainWindow)
        self.button_main_min.setStyleSheet("QPushButton {border: none;}")
        self.button_main_min.setIcon(QIcon(r"ui\min.png"))
        self.button_main_min.resize(50, 50)
        self.button_main_min.move(self.mWw - 100, 0)
        self.button_main_min.clicked.connect(self.mainWindow.showMinimized)
# ————————————————————————————————————————————————————————————
        self.showWindow = QMainWindow_new()
        self.showWindow.setFixedSize(self.di[self.dil][0]+self.di[self.dil][1]+80, self.di[self.dil][1]+500)
        self.showWindow.move(850, 300)

        self.label_backdrop = QLabel(self.showWindow)
        self.label_backdrop.resize(self.di[self.dil][0]+self.di[self.dil][1]+80, self.di[self.dil][1]+500)
        self.label_backdrop.setStyleSheet("background-color: rgb(240, 250, 250);")

        self.label_show_title = QLabel(self.showWindow)
        self.label_show_title.resize(self.di[self.dil][0]+self.di[self.dil][1]+80, 50)
        self.label_show_title.setText("    效果展示")
        self.label_show_title.setFont(QtGui.QFont("Adobe 黑体 Std R", 16))
        self.label_show_title.setStyleSheet("background-color: rgb(50, 200, 200);")

        self.label_show_T = QLabel(self.showWindow)
        self.label_show_T.resize(40, 40)
        self.label_show_T.move(5, 5)
        self.label_show_T.setPixmap(QPixmap(r"ui\label.jpg").scaled(self.label_show_T.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))

        self.button_show_close = QPushButton(self.showWindow)
        self.button_show_close.setStyleSheet("QPushButton {border: none;}")
        self.button_show_close.setIcon(QIcon(r"ui\close.png"))
        self.button_show_close.resize(50, 50)
        self.button_show_close.move(self.di[self.dil][0]+self.di[self.dil][1]+30, 0)
        self.button_show_close.clicked.connect(self.showWindow.close)

        self.button_show_min = QPushButton(self.showWindow)
        self.button_show_min.setStyleSheet("QPushButton {border: none;}")
        self.button_show_min.setIcon(QIcon(r"ui\min.png"))
        self.button_show_min.resize(50, 50)
        self.button_show_min.move(self.di[self.dil][0]+self.di[self.dil][1]-20, 0)
        self.button_show_min.clicked.connect(self.showWindow.showMinimized)
# ————————————————————————————————————————————————————————————
        self.show_label = QLabel(self.showWindow)
        self.show_label.setStyleSheet("background-color: rgb(0, 0, 0);")
        self.show_label.setAlignment(Qt.AlignCenter)
        self.show_label.setObjectName("图片显示")
        self.show_label.setCursor(Qt.CrossCursor)
        self.show_label.resize(self.di[self.dil][0], self.di[self.dil][1])
        self.show_label.move(40, 90)
# ————————————————————————————————————————————————————————————
        self.A3D_label = QWidget(self.showWindow)
        self.layout1 = QVBoxLayout(self.A3D_label)
        self.canvas = MplCanvas()
        self.layout1.addWidget(self.canvas)
        self.A3D_label.resize(self.di[self.dil][1]+20, self.di[self.dil][1]+20)
        self.A3D_label.move(self.di[self.dil][0]+30, 80)
# ————————————————————————————————————————————————————————————
        self.target_label1 = QLabel(self.showWindow)
        self.target_label1.move(self.di[self.dil][0]+45, self.di[self.dil][1]+90)
        self.target_label1.resize(self.di[self.dil][1]//3, 370)
        self.target_label1.setFont(self.font1)
        self.target_label1.setText("名字(N):{}\n\n坐标(X):{:.2f}\n\n坐标(Y):{:.2f}\n\n坐标(Z):{:.2f}\n\n距离(L):{:.2f}\n\n单位(U): cm".format(None,0,0,0,0))
# ————————————————————————————————————————————————————————————
        self.target_label2 = QLabel(self.showWindow)
        self.target_label2.move(self.di[self.dil][0]+self.di[self.dil][1]//3+40, self.di[self.dil][1]+90)
        self.target_label2.resize((self.di[self.dil][1]//3)*2, 370)
        self.target_label2.setStyleSheet("background-color: rgb(0, 0, 0);")
# ————————————————————————————————————————————————————————————
        self.target_listWidget = QListWidget(self.showWindow)
        self.target_listWidget.setLayoutDirection(Qt.LeftToRight)
        self.target_listWidget.resize(self.di[self.dil][0], 150)
        self.target_listWidget.move(40, self.di[self.dil][1] + 90)
        self.target_listWidget.setViewMode(QListWidget.IconMode)
        self.target_listWidget.setResizeMode(QListWidget.Adjust)
        self.target_listWidget.setMovement(QListWidget.Static)
        self.target_listWidget.setWrapping(True)
        self.target_listWidget.setWordWrap(True)
        self.target_listWidget.setIconSize(QSize(20, 20))
        self.target_listWidget.setIconSize(QSize(20, 20))
        self.target_listWidget.setFlow(QListView.Flow(1))
        self.target_listWidget.setIconSize(QSize(150, 100))
        self.target_listWidget.itemSelectionChanged.connect(self.change_target)
# ————————————————————————————————————————————————————————————
        self.batch_listWidget = QListWidget(self.showWindow)
        self.batch_listWidget.setLayoutDirection(Qt.LeftToRight)
        self.batch_listWidget.resize(self.di[self.dil][0], 150)
        self.batch_listWidget.move(40, self.di[self.dil][1] + 255)
        self.batch_listWidget.setViewMode(QListWidget.IconMode)
        self.batch_listWidget.setResizeMode(QListWidget.Adjust)
        self.batch_listWidget.setMovement(QListWidget.Static)
        self.batch_listWidget.setWrapping(True)
        self.batch_listWidget.setWordWrap(True)
        self.batch_listWidget.setIconSize(QSize(20, 20))
        self.batch_listWidget.setFlow(QListView.Flow(1))
        self.batch_listWidget.setIconSize(QSize(150, 100))
        self.batch_listWidget.itemSelectionChanged.connect(self.change_pictrue)
# ————————————————————————————————————————————————————————————
        self.pause_button = QPushButton(self.showWindow)
        self.pause_button.setText("暂停")
        self.pause_button.resize(80, 40)
        self.pause_button.move(self.di[self.dil][0] - 140, self.di[self.dil][1] + 420)
        self.pause_button.clicked.connect(self.pause_predict)
# ————————————————————————————————————————————————————————————
        self.end_button = QPushButton(self.showWindow)
        self.end_button.setText("终止")
        self.end_button.resize(80, 40)
        self.end_button.move(self.di[self.dil][0] - 40, self.di[self.dil][1] + 420)
        self.end_button.clicked.connect(self.end_predict)
# ————————————————————————————————————————————————————————————
        self.progressbar = QProgressBar(self.showWindow)
        self.progressbar.resize(self.di[self.dil][0] - 180, 40)
        self.progressbar.move(40, self.di[self.dil][1] + 420)
# ————————————————————————————————————————————————————————————
        basic_setting = QLabel(self.mainWindow)
        basic_setting.setText("基础设置")
        basic_setting.setFont(self.font1)
        basic_setting.resize(120, 30)
        basic_setting.move(30, 80)
# ————————————————————————————————————————————————————————————
        model_label = QLabel(self.mainWindow)
        model_label.setText("选取模型:")
        model_label.setFont(self.font2)
        model_label.resize(120,30)
        model_label.move(40,150)

        self.model_lineEdit = QLineEdit(self.mainWindow)
        self.model_lineEdit.setText(self.D["model"])
        self.model_lineEdit.resize(300,30)
        self.model_lineEdit.move(160,150)

        model_button = QPushButton(self.mainWindow)
        model_button.setText("file")
        model_button.resize(70,30)
        model_button.move(470,150)
        model_button.clicked.connect(lambda : self.select_path(item="model"))
# ————————————————————————————————————————————————————————————
        monocular_label = QLabel(self.mainWindow)
        monocular_label.setText("单目检测:")
        monocular_label.setFont(self.font2)
        monocular_label.resize(120, 30)
        monocular_label.move(40, 220)

        self.monocular_radioButton = QRadioButton(self.mainWindow)
        self.monocular_radioButton.setChecked(self.D["Monocular"])
        self.monocular_radioButton.move(180,223)
        self.monocular_radioButton.toggled.connect(self.set_source)
# ————————————————————————————————————————————————————————————
        high_label = QLabel(self.mainWindow)
        high_label.setText("高:     cm")
        high_label.setFont(self.font2)
        high_label.resize(200, 30)
        high_label.move(260,220)

        self.high_lineEdit = QLineEdit(self.mainWindow)
        self.high_lineEdit.setText(str(self.D["high"]))
        self.high_lineEdit.resize(60,30)
        self.high_lineEdit.move(300,220)
        self.high_lineEdit.setEnabled(self.monocular_radioButton.isChecked())

        wide_label = QLabel(self.mainWindow)
        wide_label.setText("宽:     cm")
        wide_label.setFont(self.font2)
        wide_label.resize(200,30)
        wide_label.move(410,220)

        self.wide_lineEdit = QLineEdit(self.mainWindow)
        self.wide_lineEdit.setText(str(self.D["wide"]))
        self.wide_lineEdit.resize(60, 30)
        self.wide_lineEdit.move(450, 220)
        self.wide_lineEdit.setEnabled(self.monocular_radioButton.isChecked())
# ————————————————————————————————————————————————————————————
        source_label = QLabel(self.mainWindow)
        source_label.setText("主 视 角:")
        source_label.setFont(self.font2)
        source_label.resize(120, 30)
        source_label.move(40, 270)

        self.source_lineEdit = QLineEdit(self.mainWindow)
        self.source_lineEdit.setText(self.D["source"])
        self.source_lineEdit.resize(300, 30)
        self.source_lineEdit.move(160, 270)
        self.source_lineEdit.setEnabled(self.monocular_radioButton.isChecked())

        self.source_batton1 = QPushButton(self.mainWindow)
        self.source_batton1.setText("f")
        self.source_batton1.resize(30, 30)
        self.source_batton1.move(470, 270)
        self.source_batton1.clicked.connect(lambda: self.select_path(item="source_f"))
        self.source_batton1.setEnabled(self.monocular_radioButton.isChecked())

        self.source_batton2 = QPushButton(self.mainWindow)
        self.source_batton2.setText("d")
        self.source_batton2.resize(30, 30)
        self.source_batton2.move(510, 270)
        self.source_batton2.clicked.connect(lambda: self.select_path(item="source_d"))
        self.source_batton2.setEnabled(self.monocular_radioButton.isChecked())
#————————————————————————————————————————————————————————————
        focalLengthl_Label = QLabel(self.mainWindow)
        focalLengthl_Label.setText("焦距l:  lfx:        px    lfy:        px")
        focalLengthl_Label.setFont(self.font2)
        focalLengthl_Label.resize(500, 30)
        focalLengthl_Label.move(40, 340)

        self.fxl_LineEdit = QLineEdit(self.mainWindow)
        self.fxl_LineEdit.setText(str(self.D["lfx"]))
        self.fxl_LineEdit.resize(80, 30)
        self.fxl_LineEdit.move(190, 340)

        self.fyl_LineEdit = QLineEdit(self.mainWindow)
        self.fyl_LineEdit.setText(str(self.D["lfy"]))
        self.fyl_LineEdit.resize(80, 30)
        self.fyl_LineEdit.move(410, 340)
# ————————————————————————————————————————————————————————————
        principalPointl_Label = QLabel(self.mainWindow)
        principalPointl_Label.setText("主点l:  lu0:        px    lv0:        px")
        principalPointl_Label.setFont(self.font2)
        principalPointl_Label.resize(500, 30)
        principalPointl_Label.move(40, 390)

        self.u0l_LineEdit = QLineEdit(self.mainWindow)
        self.u0l_LineEdit.setText(str(self.D["lu0"]))
        self.u0l_LineEdit.resize(80, 30)
        self.u0l_LineEdit.move(190, 390)

        self.v0l_LineEdit = QLineEdit(self.mainWindow)
        self.v0l_LineEdit.setText(str(self.D["lv0"]))
        self.v0l_LineEdit.resize(80, 30)
        self.v0l_LineEdit.move(410, 390)
# ————————————————————————————————————————————————————————————
        focalLengthr_Label = QLabel(self.mainWindow)
        focalLengthr_Label.setText("焦距r:  rfx:        px    rfy:        px")
        focalLengthr_Label.setFont(self.font2)
        focalLengthr_Label.resize(500, 30)
        focalLengthr_Label.move(40, 440)

        self.fxr_LineEdit = QLineEdit(self.mainWindow)
        self.fxr_LineEdit.setText(str(self.D["rfx"]))
        self.fxr_LineEdit.resize(80, 30)
        self.fxr_LineEdit.move(190, 440)
        self.fxr_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())

        self.fyr_LineEdit = QLineEdit(self.mainWindow)
        self.fyr_LineEdit.setText(str(self.D["rfy"]))
        self.fyr_LineEdit.resize(80, 30)
        self.fyr_LineEdit.move(410, 440)
        self.fyr_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())
# ————————————————————————————————————————————————————————————
        principalPointr_Label = QLabel(self.mainWindow)
        principalPointr_Label.setText("主点r:  ru0:        px    rv0:        px")
        principalPointr_Label.setFont(self.font2)
        principalPointr_Label.resize(500, 30)
        principalPointr_Label.move(40, 490)

        self.u0r_LineEdit = QLineEdit(self.mainWindow)
        self.u0r_LineEdit.setText(str(self.D["ru0"]))
        self.u0r_LineEdit.resize(80, 30)
        self.u0r_LineEdit.move(190, 490)
        self.u0r_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())

        self.v0r_LineEdit = QLineEdit(self.mainWindow)
        self.v0r_LineEdit.setText(str(self.D["rv0"]))
        self.v0r_LineEdit.resize(80, 30)
        self.v0r_LineEdit.move(410, 490)
        self.v0r_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())
# ————————————————————————————————————————————————————————————
        binocular_label = QLabel(self.mainWindow)
        binocular_label.setText("双目检测:")
        binocular_label.setFont(self.font2)
        binocular_label.resize(150, 30)
        binocular_label.move(40, 560)

        self.binocular_radiobutton = QRadioButton(self.mainWindow)
        self.binocular_radiobutton.setChecked(not self.D["Monocular"])
        self.binocular_radiobutton.move(180, 563)
        self.binocular_radiobutton.toggled.connect(self.set_source)
# ————————————————————————————————————————————————————————————
#         focalLength_label = QLabel(self.mainWindow)
#         focalLength_label.setText("焦距:")
#         focalLength_label.setFont(self.font2)
#         focalLength_label.resize(150,30)
#         focalLength_label.move(210,510)
#
#         self.focalLength_lineEdit = QLineEdit(self.mainWindow)
#         self.focalLength_lineEdit.setText(str(self.D["focalLength"]))
#         self.focalLength_lineEdit.resize(50,30)
#         self.focalLength_lineEdit.move(280,510)
#         self.focalLength_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())
#
#         focalLength_label1 = QLabel(self.mainWindow)
#         focalLength_label1.setText("pt")
#         focalLength_label1.setFont(self.font3)
#         focalLength_label1.resize(50, 30)
#         focalLength_label1.move(337, 510)
# ————————————————————————————————————————————————————————————
        spaceBetween_label = QLabel(self.mainWindow)
        spaceBetween_label.setText("两摄像头的间距:     cm")
        spaceBetween_label.setFont(self.font2)
        spaceBetween_label.resize(300,30)
        spaceBetween_label.move(260,560)

        self.spaceBetween_lineEdit = QLineEdit(self.mainWindow)
        self.spaceBetween_lineEdit.setText(str(self.D["spaceBetween"]))
        self.spaceBetween_lineEdit.resize(50, 30)
        self.spaceBetween_lineEdit.move(450, 560)
        self.spaceBetween_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())
# ————————————————————————————————————————————————————————————
        left_label = QLabel(self.mainWindow)
        left_label.setText("左 视 角:")
        left_label.setFont(self.font2)
        left_label.resize(120, 30)
        left_label.move(40, 610)

        self.left_lineEdit = QLineEdit(self.mainWindow)
        self.left_lineEdit.setText(self.D["leftView"])
        self.left_lineEdit.resize(300, 30)
        self.left_lineEdit.move(160, 610)
        self.left_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())

        self.left_batton1 = QPushButton(self.mainWindow)
        self.left_batton1.setText("f")
        self.left_batton1.resize(30, 30)
        self.left_batton1.move(470, 610)
        self.left_batton1.setEnabled(self.binocular_radiobutton.isChecked())
        self.left_batton1.clicked.connect(lambda :self.select_path(item="left_f"))

        self.left_batton2 = QPushButton(self.mainWindow)
        self.left_batton2.setText("d")
        self.left_batton2.resize(30, 30)
        self.left_batton2.move(510, 610)
        self.left_batton2.setEnabled(self.binocular_radiobutton.isChecked())
        self.left_batton2.clicked.connect(lambda :self.select_path(item="left_d"))
# ————————————————————————————————————————————————————————————
        right_label = QLabel(self.mainWindow)
        right_label.setText("右 视 角:")
        right_label.setFont(self.font2)
        right_label.resize(120, 30)
        right_label.move(40, 660)

        self.right_lineEdit = QLineEdit(self.mainWindow)
        self.right_lineEdit.setText(self.D["rightView"])
        self.right_lineEdit.resize(300, 30)
        self.right_lineEdit.move(160, 660)
        self.right_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())

        self.right_batton1 = QPushButton(self.mainWindow)
        self.right_batton1.setText("f")
        self.right_batton1.resize(30, 30)
        self.right_batton1.move(470, 660)
        self.right_batton1.setEnabled(self.binocular_radiobutton.isChecked())
        self.right_batton1.clicked.connect(lambda :self.select_path(item="right_f"))

        self.right_batton2 = QPushButton(self.mainWindow)
        self.right_batton2.setText("d")
        self.right_batton2.resize(30, 30)
        self.right_batton2.move(510, 660)
        self.right_batton2.setEnabled(self.binocular_radiobutton.isChecked())
        self.right_batton2.clicked.connect(lambda : self.select_path(item="right_d"))
# ————————————————————————————————————————————————————————————
        self.save_checkBox = QCheckBox(self.mainWindow)
        self.save_checkBox.setFont(self.font3)
        self.save_checkBox.setChecked(self.D["save"])
        self.save_checkBox.setStyleSheet("QCheckBox::indicator {width: 24px; height: 24px;}")
        self.save_checkBox.move(515, 730)
        self.save_checkBox.stateChanged.connect(self.set_save)

        save_path_label = QLabel(self.mainWindow)
        save_path_label.setText("保存路径:")
        save_path_label.setFont(self.font2)
        save_path_label.resize(120, 30)
        save_path_label.move(40, 730)

        self.save_path_lineEdit = QLineEdit(self.mainWindow)
        self.save_path_lineEdit.setText(self.D["save_path"])
        self.save_path_lineEdit.resize(300, 30)
        self.save_path_lineEdit.move(160, 730)
        self.save_path_lineEdit.setEnabled(self.save_checkBox.isChecked())

        self.save_path_button = QPushButton(self.mainWindow)
        self.save_path_button.setText("d")
        self.save_path_button.resize(30, 30)
        self.save_path_button.move(470, 730)
        self.save_path_button.clicked.connect(lambda :self.select_path(item="save"))
        self.save_path_button.setEnabled(self.save_checkBox.isChecked())

        Camera_detection=QButtonGroup(self.mainWindow)
        Camera_detection.addButton(self.binocular_radiobutton)
        Camera_detection.addButton(self.monocular_radioButton)
# ————————————————————————————————————————————————————————————
        saveSetting = QPushButton(self.mainWindow)
        saveSetting.setText("保存设置")
        saveSetting.setFont(self.font3)
        saveSetting.resize(120,40)
        saveSetting.move(40,self.mWh-80)
        saveSetting.clicked.connect(self.save_setting)
# ————————————————————————————————————————————————————————————
        startPredict = QPushButton(self.mainWindow)
        startPredict.setText("开始检测")
        startPredict.setFont(self.font3)
        startPredict.resize(120,40)
        startPredict.move(180,self.mWh-80)
        startPredict.clicked.connect(self.start_predict)
# ————————————————————————————————————————————————————————————
        self.detail_set_button = QPushButton(self.mainWindow)
        self.detail_set_button.setText("详细设置>")
        self.detail_set_button.setFont(self.font3)
        self.detail_set_button.resize(120, 40)
        self.detail_set_button.move(430, self.mWh - 80)
        self.detail_set_button.clicked.connect(self.detail_set_window)
# ————————————————————————————————————————————————————————————
        detail_setting = QLabel(self.mainWindow)
        detail_setting.setFont(self.font1)
        detail_setting.setText("详细设置")
        detail_setting.resize(120,30)
        detail_setting.move(600,80)
# ————————————————————————————————————————————————————————————
        augment_label = QLabel(self.mainWindow)
        augment_label.setText("图像增强:")
        augment_label.setFont(self.font2)
        augment_label.resize(120, 30)
        augment_label.move(610, 150)

        self.augment_button = QCheckBox(self.mainWindow)
        self.augment_button.setText("开启")
        self.augment_button.setFont(self.font3)
        self.augment_button.setChecked(self.D["augment"])
        self.augment_button.move(745, 150)
# ————————————————————————————————————————————————————————————
        half_label = QLabel(self.mainWindow)
        half_label.setText("半精度:")
        half_label.setFont(self.font2)
        half_label.resize(120, 30)
        half_label.move(840, 150)

        self.half_button = QCheckBox(self.mainWindow)
        self.half_button.setText("开启")
        self.half_button.setFont(self.font3)
        self.half_button.setChecked(self.D["half"])
        self.half_button.move(945, 150)
# ————————————————————————————————————————————————————————————
        retina_masks_label = QLabel(self.mainWindow)
        retina_masks_label.setText("分割掩膜:")
        retina_masks_label.setFont(self.font2)
        retina_masks_label.resize(120, 30)
        retina_masks_label.move(610, 210)

        self.retina_masks_button = QCheckBox(self.mainWindow)
        self.retina_masks_button.setText("开启")
        self.retina_masks_button.setFont(self.font3)
        self.retina_masks_button.setChecked(self.D["retina_masks"])
        self.retina_masks_button.move(745, 210)
# ————————————————————————————————————————————————————————————
        agnostic_nms_label = QLabel(self.mainWindow)
        agnostic_nms_label.setText("N_M_S:")
        agnostic_nms_label.setFont(self.font2)
        agnostic_nms_label.resize(100, 30)
        agnostic_nms_label.move(840, 210)

        self.agnostic_nms_button = QCheckBox(self.mainWindow)
        self.agnostic_nms_button.setText("开启")
        self.agnostic_nms_button.setFont(self.font3)
        self.agnostic_nms_button.setChecked(self.D["agnostic_nms"])
        self.agnostic_nms_button.move(945, 210)
# ————————————————————————————————————————————————————————————
        draw_probs_label = QLabel(self.mainWindow)
        draw_probs_label.setText("绘制分类:")
        draw_probs_label.setFont(self.font2)
        draw_probs_label.resize(120, 30)
        draw_probs_label.move(610, 270)

        self.draw_probs_checkBox = QCheckBox(self.mainWindow)
        self.draw_probs_checkBox.setChecked(self.D["draw_probs"])
        self.draw_probs_checkBox.setText("开启")
        self.draw_probs_checkBox.setFont(self.font3)
        self.draw_probs_checkBox.resize(70, 30)
        self.draw_probs_checkBox.move(745, 270)
# ————————————————————————————————————————————————————————————
        use_pil_label = QLabel(self.mainWindow)
        use_pil_label.setText("使用pil:")
        use_pil_label.setFont(self.font2)
        use_pil_label.resize(120, 30)
        use_pil_label.move(840, 270)

        self.use_pil_checkBox = QCheckBox(self.mainWindow)
        self.use_pil_checkBox.setChecked(self.D["use_pil"])
        self.use_pil_checkBox.setText("开启")
        self.use_pil_checkBox.setFont(self.font3)
        self.use_pil_checkBox.resize(70, 30)
        self.use_pil_checkBox.move(945, 270)
# ————————————————————————————————————————————————————————————
        show_label = QLabel(self.mainWindow)
        show_label.setText("显示设置:")
        show_label.setFont(self.font2)
        show_label.resize(120, 30)
        show_label.move(610, 340)

        self.show_labels_checkBox = QCheckBox(self.mainWindow)
        self.show_labels_checkBox.setChecked(self.D["show_labels"])
        self.show_labels_checkBox.setText("显示标签")
        self.show_labels_checkBox.setFont(self.font3)
        self.show_labels_checkBox.resize(170,30)
        self.show_labels_checkBox.move(630,390)

        self.show_conf_checkBox = QCheckBox(self.mainWindow)
        self.show_conf_checkBox.setChecked(self.D["show_conf"])
        self.show_conf_checkBox.setText("显示分数")
        self.show_conf_checkBox.setFont(self.font3)
        self.show_conf_checkBox.resize(170, 30)
        self.show_conf_checkBox.move(830, 390)

        self.show_coordinate_checkBox = QCheckBox(self.mainWindow)
        self.show_coordinate_checkBox.setChecked(self.D["show_coordinate"])
        self.show_coordinate_checkBox.setText("显示坐标")
        self.show_coordinate_checkBox.setFont(self.font3)
        self.show_coordinate_checkBox.resize(170, 30)
        self.show_coordinate_checkBox.move(630, 440)

        self.show_fps_checkBox = QCheckBox(self.mainWindow)
        self.show_fps_checkBox.setChecked(self.D["show_fps"])
        self.show_fps_checkBox.setText("显示fps")
        self.show_fps_checkBox.setFont(self.font3)
        self.show_fps_checkBox.resize(170, 30)
        self.show_fps_checkBox.move(830, 440)

        self.show_boxes_checkBox = QCheckBox(self.mainWindow)
        self.show_boxes_checkBox.setChecked(self.D["show_boxes"])
        self.show_boxes_checkBox.setText("显示边框")
        self.show_boxes_checkBox.setFont(self.font3)
        self.show_boxes_checkBox.resize(170, 30)
        self.show_boxes_checkBox.move(630, 490)

        self.show_masks_checkBox = QCheckBox(self.mainWindow)
        self.show_masks_checkBox.setChecked(self.D["show_masks"])
        self.show_masks_checkBox.setText("显示掩膜")
        self.show_masks_checkBox.setFont(self.font3)
        self.show_masks_checkBox.resize(170, 30)
        self.show_masks_checkBox.move(830, 490)
# ————————————————————————————————————————————————————————————
        line_width_label = QLabel(self.mainWindow)
        line_width_label.setText("边框线宽:")
        line_width_label.setFont(self.font2)
        line_width_label.resize(120, 30)
        line_width_label.move(610, 560)

        self.line_width_lineEidt = QLineEdit(self.mainWindow)
        self.line_width_lineEidt.setText(str(self.D["line_width"]))
        self.line_width_lineEidt.resize(50, 30)
        self.line_width_lineEidt.move(755, 560)
# ————————————————————————————————————————————————————————————
        font_size_label = QLabel(self.mainWindow)
        font_size_label.setText("字体大小:")
        font_size_label.setFont(self.font2)
        font_size_label.resize(120, 30)
        font_size_label.move(840, 560)

        self.font_size_lineEidt = QLineEdit(self.mainWindow)
        self.font_size_lineEidt.setText(str(self.D["font_size"]))
        self.font_size_lineEidt.resize(50, 30)
        self.font_size_lineEidt.move(960, 560)
# ————————————————————————————————————————————————————————————
        conf_label = QLabel(self.mainWindow)
        conf_label.setText("信任度阈值:")
        conf_label.setFont(self.font2)
        conf_label.resize(150, 30)
        conf_label.move(610, 620)

        self.conf_lineEidt = QLineEdit(self.mainWindow)
        self.conf_lineEidt.setText(str(self.D["conf"]))
        self.conf_lineEidt.resize(50, 30)
        self.conf_lineEidt.move(755, 620)
# ————————————————————————————————————————————————————————————
        iou_label = QLabel(self.mainWindow)
        iou_label.setText("iou阈值:")
        iou_label.setFont(self.font2)
        iou_label.resize(120, 30)
        iou_label.move(850, 620)

        self.iou_lineEidt = QLineEdit(self.mainWindow)
        self.iou_lineEidt.setText(str(self.D["iou"]))
        self.iou_lineEidt.resize(50, 30)
        self.iou_lineEidt.move(960, 620)
# ————————————————————————————————————————————————————————————
        max_det_label = QLabel(self.mainWindow)
        max_det_label.setText("最大检测数:")
        max_det_label.setFont(self.font2)
        max_det_label.resize(170, 30)
        max_det_label.move(610, 680)

        self.max_det_lineEdit = QLineEdit(self.mainWindow)
        self.max_det_lineEdit.setText(str(self.D["max_det"]))
        self.max_det_lineEdit.resize(50, 30)
        self.max_det_lineEdit.move(755, 680)
# ————————————————————————————————————————————————————————————
        device_label = QLabel(self.mainWindow)
        device_label.setText("运行设备:")
        device_label.setFont(self.font2)
        device_label.resize(170, 30)
        device_label.move(840, 680)

        self.device_lineEdit = QLineEdit(self.mainWindow)
        self.device_lineEdit.setText(str(self.D["device"]))
        self.device_lineEdit.resize(50, 30)
        self.device_lineEdit.move(960, 680)
# ————————————————————————————————————————————————————————————
        device_label = QLabel(self.mainWindow)
        device_label.setText("运行设备:")
        device_label.setFont(self.font2)
        device_label.resize(170, 30)
        device_label.move(840, 680)

        self.device_lineEdit = QLineEdit(self.mainWindow)
        self.device_lineEdit.setText(str(self.D["device"]))
        self.device_lineEdit.resize(50, 30)
        self.device_lineEdit.move(960, 680)
# ————————————————————————————————————————————————————————————
        Binocular_show_label = QLabel(self.mainWindow)
        Binocular_show_label.setText("双目检测显示图:")
        Binocular_show_label.setFont(self.font2)
        Binocular_show_label.resize(200, 30)
        Binocular_show_label.move(610, 750)

        Binocular_show_left = QRadioButton(self.mainWindow)
        Binocular_show_left.setText("左")
        Binocular_show_left.setFont(self.font3)
        Binocular_show_left.resize(50, 30)
        Binocular_show_left.move(810, 750)

        Binocular_show_right = QRadioButton(self.mainWindow)
        Binocular_show_right.setText("右")
        Binocular_show_right.setFont(self.font3)
        Binocular_show_right.resize(50, 30)
        Binocular_show_right.move(885, 750)

        Binocular_show_combine = QRadioButton(self.mainWindow)
        Binocular_show_combine.setText("合")
        Binocular_show_combine.setFont(self.font3)
        Binocular_show_combine.resize(50, 30)
        Binocular_show_combine.move(960, 750)

        Binocular_show_combine.setChecked(True)
        self.layout = QButtonGroup(self.mainWindow)
        self.layout.addButton(Binocular_show_left)
        self.layout.addButton(Binocular_show_right)
        self.layout.addButton(Binocular_show_combine)
# ————————————————————————————————————————————————————————————
        show_size_label = QLabel(self.mainWindow)
        show_size_label.setText("效果界面尺寸:")
        show_size_label.setFont(self.font2)
        show_size_label.resize(200, 30)
        show_size_label.move(610, 810)

        self.show_size = QLabel(self.mainWindow)
        self.show_size.setText(self.size_dic[self.D["show_size"]])
        self.show_size.setFont(self.font2)
        self.show_size.resize(50, 30)
        self.show_size.move(770, 810)

        self.show_size_reduce = QPushButton(self.mainWindow)
        self.show_size_reduce.setText("-")
        self.show_size_reduce.resize(30, 30)
        self.show_size_reduce.move(820, 810)
        self.show_size_reduce.clicked.connect(lambda :self.set_show_window(0))

        self.show_size_big = QPushButton(self.mainWindow)
        self.show_size_big.setText("+")
        self.show_size_big.resize(30, 30)
        self.show_size_big.move(860, 810)
        self.show_size_big.clicked.connect(lambda: self.set_show_window(1))

        self.preview = QPushButton(self.mainWindow)
        self.preview.setText("预览")
        self.preview.resize(100, 30)
        self.preview.move(910, 810)
        self.preview.clicked.connect(lambda: self.set_show_window(2))
# ————————————————————————————————————————————————————————————
    def detail_set_window(self):
        if self.detail_set_button.text()=="详细设置>":
            self.mainWindow.setFixedSize(1050, self.mWh)
            self.label_main_title.resize(1050, 50)
            self.button_main_close.move(1000, 0)
            self.button_main_min.move(950, 0)
            self.detail_set_button.setText("详细设置<")
        else:
            self.mainWindow.setFixedSize(590, self.mWh)
            self.label_main_title.resize(590, 50)
            self.button_main_close.move(540, 0)
            self.button_main_min.move(490, 0)
            self.detail_set_button.setText("详细设置>")

    def set_show_window(self, i):
        if i==0 and self.dil!=0:
            self.dil -= 1
            self.show_size.setText(self.size_dic[self.dil])

            self.label_backdrop.resize(self.di[self.dil][0] + self.di[self.dil][1] + 80, self.di[self.dil][1] + 500)
            self.label_show_title.resize(self.di[self.dil][0] + self.di[self.dil][1] + 80, 50)
            self.button_show_close.move(self.di[self.dil][0] + self.di[self.dil][1] + 30, 0)
            self.button_show_min.move(self.di[self.dil][0] + self.di[self.dil][1] - 20, 0)

            self.show_label.resize(self.di[self.dil][0], self.di[self.dil][1])
            self.showWindow.setFixedSize(self.di[self.dil][0]+self.di[self.dil][1]+80, self.di[self.dil][1]+500)
            self.pause_button.move(self.di[self.dil][0] - 140, self.di[self.dil][1] + 420)
            self.end_button.move(self.di[self.dil][0] - 40, self.di[self.dil][1] + 420)
            self.progressbar.resize(self.di[self.dil][0] - 180, 40)
            self.progressbar.move(40, self.di[self.dil][1] + 420)
            self.A3D_label.resize(self.di[self.dil][1] + 20, self.di[self.dil][1] + 20)
            self.A3D_label.move(self.di[self.dil][0] + 30, 80)
            self.batch_listWidget.resize(self.di[self.dil][0], 150)
            self.batch_listWidget.move(40, self.di[self.dil][1] + 255)
            self.target_listWidget.resize(self.di[self.dil][0], 150)
            self.target_listWidget.move(40, self.di[self.dil][1] + 90)
            self.target_label1.move(self.di[self.dil][0] + 45, self.di[self.dil][1] + 90)
            self.target_label1.resize(self.di[self.dil][1] // 3, 370)
            self.target_label2.move(self.di[self.dil][0] + self.di[self.dil][1] // 3 + 40, self.di[self.dil][1] + 90)
            self.target_label2.resize((self.di[self.dil][1] // 3) * 2, 370)
        elif i==1 and self.dil!=2:
            self.dil+=1
            self.show_size.setText(self.size_dic[self.dil])

            self.label_backdrop.resize(self.di[self.dil][0] + self.di[self.dil][1] + 80, self.di[self.dil][1] + 500)
            self.label_show_title.resize(self.di[self.dil][0] + self.di[self.dil][1] + 80, 50)
            self.button_show_close.move(self.di[self.dil][0] + self.di[self.dil][1] + 30, 0)
            self.button_show_min.move(self.di[self.dil][0] + self.di[self.dil][1] - 20, 0)

            self.show_label.resize(self.di[self.dil][0], self.di[self.dil][1])
            self.showWindow.setFixedSize(self.di[self.dil][0] + self.di[self.dil][1] + 80, self.di[self.dil][1] + 500)
            self.pause_button.move(self.di[self.dil][0] - 140, self.di[self.dil][1] + 420)
            self.end_button.move(self.di[self.dil][0] - 40, self.di[self.dil][1] + 420)
            self.progressbar.resize(self.di[self.dil][0] - 180, 40)
            self.progressbar.move(40, self.di[self.dil][1] + 420)
            self.A3D_label.resize(self.di[self.dil][1] + 20, self.di[self.dil][1] + 20)
            self.A3D_label.move(self.di[self.dil][0] + 30, 80)
            self.batch_listWidget.resize(self.di[self.dil][0], 150)
            self.batch_listWidget.move(40, self.di[self.dil][1] + 255)
            self.target_listWidget.resize(self.di[self.dil][0], 150)
            self.target_listWidget.move(40, self.di[self.dil][1] + 90)
            self.target_label1.move(self.di[self.dil][0] + 45, self.di[self.dil][1] + 90)
            self.target_label1.resize(self.di[self.dil][1] // 3, 370)
            self.target_label2.move(self.di[self.dil][0] + self.di[self.dil][1] // 3 + 40, self.di[self.dil][1] + 90)
            self.target_label2.resize((self.di[self.dil][1] // 3) * 2, 370)
        elif i==2:
            self.showWindow.show()

    # 选择路径
    def select_path(self,item):
        if item=="model":
            path, _ = QFileDialog.getOpenFileName(filter="*.pt;*.ckpt;")
            if path != "":
                self.model_lineEdit.setText(path)
        elif item=="source_f":#选取检测源(文件)
            path, _ = QFileDialog.getOpenFileName()
            if path != "":
                self.source_lineEdit.setText(path)
        elif item=="source_d":#选取检测源(文件夹)
            path = QFileDialog.getExistingDirectory()
            if path != "":
                self.source_lineEdit.setText(path)
        elif item=="left_f":
            path, _ = QFileDialog.getOpenFileName()
            if path != "":
                self.left_lineEdit.setText(path)
        elif item=="left_d":
            path = QFileDialog.getExistingDirectory()
            if path != "":
                self.left_lineEdit.setText(path)
        elif item=="right_f":
            path, _ = QFileDialog.getOpenFileName()
            if path != "":
                self.right_lineEdit.setText(path)
        elif item=="right_d":
            path = QFileDialog.getExistingDirectory()
            if path != "":
                self.right_lineEdit.setText(path)
        elif item=="save":#选择保存路径
            path = QFileDialog.getExistingDirectory()
            if path != "":
                self.save_path_lineEdit.setText(path)

    # 设置保存是否可点
    def set_save(self):
        self.save_path_lineEdit.setEnabled(self.save_checkBox.isChecked())
        self.save_path_button.setEnabled(self.save_checkBox.isChecked())

    # 设置检测源是否可点
    def set_source(self):
        self.source_lineEdit.setEnabled(self.monocular_radioButton.isChecked())
        self.source_batton1.setEnabled(self.monocular_radioButton.isChecked())
        self.source_batton2.setEnabled(self.monocular_radioButton.isChecked())

        self.wide_lineEdit.setEnabled(self.monocular_radioButton.isChecked())
        self.high_lineEdit.setEnabled(self.monocular_radioButton.isChecked())

        self.left_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())
        self.left_batton1.setEnabled(self.binocular_radiobutton.isChecked())
        self.left_batton2.setEnabled(self.binocular_radiobutton.isChecked())

        self.right_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())
        self.right_batton1.setEnabled(self.binocular_radiobutton.isChecked())
        self.right_batton2.setEnabled(self.binocular_radiobutton.isChecked())

        self.spaceBetween_lineEdit.setEnabled(self.binocular_radiobutton.isChecked())

        self.fxr_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())
        self.fyr_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())
        self.u0r_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())
        self.v0r_LineEdit.setEnabled(not self.monocular_radioButton.isChecked())

    # 保存设置
    def save_setting(self):
        self.D["model"] = self.model_lineEdit.text()

        self.D["Binocular"] = self.binocular_radiobutton.isChecked()
        self.D["high"] = float(self.high_lineEdit.text())
        self.D["wide"] = float(self.wide_lineEdit.text())

        self.D["Monocular"] = self.monocular_radioButton.isChecked()
        self.D["spaceBetween"] = float(self.spaceBetween_lineEdit.text())

        self.D["lfx"] = float(self.fxl_LineEdit.text())
        self.D["lfy"] = float(self.fyl_LineEdit.text())
        self.D["lu0"] = float(self.u0l_LineEdit.text())
        self.D["lv0"] = float(self.v0l_LineEdit.text())

        self.D["rfx"] = float(self.fxr_LineEdit.text())
        self.D["rfy"] = float(self.fyr_LineEdit.text())
        self.D["ru0"] = float(self.u0r_LineEdit.text())
        self.D["rv0"] = float(self.v0r_LineEdit.text())

        left = self.left_lineEdit.text()
        right = self.right_lineEdit.text()
        if os.path.isdir(left) == os.path.isdir(right):
            self.D["leftView"] = left
            self.D["rightView"] = right
        else:
            QMessageBox.warning(self.mainWindow, "警告", "请保持左右视图格式一致")

        self.D["source"] = self.source_lineEdit.text()

        self.D["high"] = float(self.high_lineEdit.text())
        self.D["wide"] = float(self.wide_lineEdit.text())

        self.D["save"] = self.save_checkBox.isChecked()
        self.D["save_path"] = self.save_path_lineEdit.text()

        self.D["half"] = self.half_button.isChecked()
        self.D["augment"] = self.augment_button.isChecked()
        self.D["retina_masks"] = self.retina_masks_button.isChecked()
        self.D["agnostic_nms"] = self.agnostic_nms_button.isChecked()
        self.D["draw_probs"] = self.draw_probs_checkBox.isChecked()
        self.D["use_pil"] = self.use_pil_checkBox.isChecked()

        self.D["show_labels"] = self.show_labels_checkBox.isChecked()
        self.D["show_conf"] = self.show_conf_checkBox.isChecked()
        self.D["show_boxes"] = self.show_boxes_checkBox.isChecked()
        self.D["show_masks"] = self.show_masks_checkBox.isChecked()
        self.D["show_coordinate"] = self.show_coordinate_checkBox.isChecked()
        self.D["show_fps"] = self.show_fps_checkBox.isChecked()

        line_width = self.line_width_lineEidt.text()
        if line_width.isdigit():
            self.D["line_width"] = int(line_width)
        else:
            self.D["line_width"] = None
        self.D["font_size"] = int(self.font_size_lineEidt.text())

        self.D["conf"] = float(self.conf_lineEidt.text())
        self.D["iou"] = float(self.iou_lineEidt.text())
        self.D["max_det"] = int(self.max_det_lineEdit.text())
        device = self.device_lineEdit.text()
        if device=="None":
            self.D["device"] = None
        else:
            self.D["device"] = device

        self.D["show_size"] = self.dil

        with open("runin_predict.json", "w") as file:
            json.dump(self.D,file,indent=4)
        QMessageBox.information(self.mainWindow, "操作成功", "设置完成")

    # 开始检测
    def start_predict(self):
        self.model = YOLO(self.D["model"])
        self.batch_listWidget.clear()
        self.progressbar.setValue(0)
        self.run=True
        self.showWindow.show()
        if self.D["Binocular"] == True:
            if self.D["leftView"].endswith((".jpg",".png",".bmp")) and self.D["rightView"].endswith((".jpg",".png",".bmp")):
                if self.D["leftView"] == self.D["rightView"]:
                    image = cv2.imread(self.D["leftView"])
                    h, w, _ = image.shape
                    wf = w // 2
                    image_l = image[0:h, 0:wf]
                    image_r = image[0:h, wf:w]
                else:
                    image_l = cv2.imread(self.D["leftView"])
                    image_r = cv2.imread(self.D["rightView"])
                frame, re1, re2, items = self.binocularPredict(image_l=image_l,image_r=image_r)
                if self.D["save"]:
                    cv2.imwrite(self.D["save_path"] + "/" + os.path.basename(self.D["leftView"]), frame)
                return True
            elif os.path.isdir(self.D["leftView"]) and os.path.isdir(self.D["rightView"]):
                target = self.binocularBatch
            elif self.D["leftView"].endswith(".mp4") and self.D["rightView"].endswith(".mp4"):
                target = self.binocularVidoe
            else:
                target = self.binocularRealtime
        else:
            if self.D["source"].endswith((".jpg",".png",".bmp")):
                image = cv2.imread(self.D["source"], 1)
                frame, re1, re2, items = self.monocularPredict(image=image)
                if self.D["save"]:
                    cv2.imwrite(self.D["save_path"]+"/"+os.path.basename(self.D["source"]), frame)
                return True
            elif os.path.isdir(self.D["source"]):
                target = self.monocularBatch
            elif self.D["source"].endswith(".mp4"):
                target = self.monocularVidoe
            else:
                target = self.monocularRealtime
        Thread(target=target).start()
        return True

    # 暂停检测
    def pause_predict(self):
        if self.pause_button.text()=="暂停":
            self.event.clear()
            self.pause_button.setText("继续")
        else:
            self.event.set()
            self.pause_button.setText("暂停")

    # 终止检测
    def end_predict(self):
        self.run = False

    # 更新进度条
    def update_progressbar(self,num):
        self.progressbar.setValue(num)

    # 执行检测
    def detect(self,source):
        results = self.model(source=source,
                             augment=self.D["augment"],
                             half=self.D["half"],
                             agnostic_nms=self.D["agnostic_nms"],
                             retina_masks=self.D["retina_masks"],
                             conf=self.D["conf"],
                             iou=self.D["iou"],
                             max_det=self.D["max_det"],
                             device=self.D["device"])

        results[0].boxes.data = list(results[0].boxes.data)
        images=list()
        for i in results:
            images.append(i.plot(probs=self.D["draw_probs"],
                                 pil=self.D["use_pil"],
                                 labels=self.D["show_labels"],
                                 conf=self.D["show_conf"],
                                 boxes=self.D["show_boxes"],
                                 masks=self.D["show_masks"],
                                 line_width=self.D["line_width"]))
        return results, images

    def show_result(self, frame):
        img_height, img_width, channels = frame.shape
        if img_height > img_width:
            frame = cv2.resize(frame, ((self.di[self.dil][1] * img_width) // img_height, self.di[self.dil][1]))
        else:
            frame = cv2.resize(frame, (self.di[self.dil][0], (self.di[self.dil][0] * img_height) // img_width))
        img_height, img_width, channels = frame.shape
        frame_Q = QImage(frame.data, img_width, img_height, channels * img_width,QImage.Format_BGR888)
        self.show_label.setPixmap(QPixmap(frame_Q))

    def plot_3D(self, N, X, Y, Z):
        self.canvas.axes.cla()
        self.canvas.axes.plot([0, 100], [0, 0], [0, 0], color='red', linewidth=1, linestyle='-')
        self.canvas.axes.plot([0, 0], [0, 0], [-50, 50], color='blue', linewidth=1, linestyle='--')
        self.canvas.axes.plot([0, 0], [-50, 50], [0, 0], color='blue', linewidth=1, linestyle='--')
        self.canvas.axes.plot(X, Y, Z, 'o')
        for i in range(len(N)):
            self.canvas.axes.text(X[i], Y[i], Z[i], N[i])
        self.canvas.axes.set_xlabel('Z')
        self.canvas.axes.set_ylabel('X')
        self.canvas.axes.set_zlabel('Y')
        self.canvas.draw()

    def change_target(self):
        Idx = self.target_listWidget.currentIndex().row()
        frame = self.target_list[Idx][0]
        Nc = self.target_list[Idx][1]
        Xc = self.target_list[Idx][2]
        Yc = self.target_list[Idx][3]
        Zc = self.target_list[Idx][4]
        Lc = self.target_list[Idx][5]
        self.target_label1.setText("名字(N):{}\n\n坐标(X):{:.2f}\n\n坐标(Y):{:.2f}\n\n坐标(Z):{:.2f}\n\n距离(L):{:.2f}\n\n单位(U): cm".format(Nc,Xc,Yc,Zc,Lc))
        # self.target_label2.resize((self.di[self.dil][1] // 3) * 2, 370)
        img_height, img_width, channels = frame.shape
        if img_height > img_width:
            frame = cv2.resize(frame, ((370 * img_width) // img_height, 370))
        else:
            frame = cv2.resize(frame, ((self.di[self.dil][1]//3)*2, ((self.di[self.dil][1]//3)*2*img_height)//img_width))
        img_height, img_width, channels = frame.shape
        frame_Q = QImage(frame.data, img_width, img_height, channels * img_width, QImage.Format_BGR888)
        self.target_label2.setPixmap(QPixmap(frame_Q))

    def change_pictrue(self):
        Idx = self.batch_listWidget.currentIndex().row()
        self.show_result(self.results_list[Idx][0])
        self.plot_3D(self.results_list[Idx][1][0], self.results_list[Idx][1][3], self.results_list[Idx][1][1], self.results_list[Idx][1][2])
        self.target_listWidget.clear()
        self.target_list = []

        for i in range(len(self.results_list[Idx][2])):
            target_image = self.results_list[Idx][2][i]
            N = self.results_list[Idx][1][0][i]
            X = self.results_list[Idx][1][1][i]
            Y = self.results_list[Idx][1][2][i]
            Z = self.results_list[Idx][1][3][i]
            L = self.results_list[Idx][1][4][i]

            qt_image = QPixmap.fromImage(self.mat_to_qimage(target_image))
            item = QListWidgetItem(QIcon(qt_image), N)
            self.target_listWidget.addItem(item)
            self.target_list.append([target_image, N, X, Y, Z, L])

    # 单目图片检测
    def monocularPredict(self, image=None):
        t1 = time.time()
        fx, fy = self.D["lfx"], self.D["lfy"]
        u0, v0 = self.D["lu0"], self.D["lv0"]
        coordinates, items = list(), list()
        N, X, Y, Z, L = [], [], [], [], []
        self.target_listWidget.clear()
        self.target_list = []
        try:
            results, images = self.detect(image)
            result, frame = results[0], images[0]
            img_height, img_width, channels = frame.shape
            for i in range(len(result.boxes.data)):
                class_name = result.names[int(result.boxes.data[i][5])]
                x = float(result.boxes.data[i][0])
                y = float(result.boxes.data[i][1])
                w = float(result.boxes.data[i][2])
                h = float(result.boxes.data[i][3])

                Zc = ((self.D["high"]*fy/abs(h-y))+(self.D["wide"]*fx/abs(w-x)))/2
                x_w, y_h = (x + w) / 2, (y + h) / 2
                Xc = -((Zc*(x_w-u0))/fx)
                Yc = -((Zc*(y_h-v0))/fy)
                Lc = (Xc**2 + Yc**2 + Zc**2)**0.5
                if self.D["show_coordinate"]:
                    frame = self.show_chinese(frame, "x:{:.2f}cm\ny:{:.2f}cm\nz:{:.2f}cm".format(Xc, Yc, Zc), (w+5, y-10), (255,250,0))


                target_image = image[int(y):int(h), int(x):int(w)]
                qt_image = QPixmap.fromImage(self.mat_to_qimage(target_image))
                item = QListWidgetItem(QIcon(qt_image), class_name)
                self.target_listWidget.addItem(item)
                self.target_list.append([target_image, class_name, Xc, Yc, Zc, Lc])
                items.append(target_image)
                N.append(class_name)
                X.append(Xc)
                Y.append(Yc)
                Z.append(Zc)
                L.append(Lc)
                coordinates.append((class_name, Xc, Yc, Zc))
        except:
            frame = image
            img_height, img_width, channels = frame.shape
        self.plot_3D(N, Z, X, Y)
        self.N, self.X, self.Y, self.Z = N, X, Y, Z
        if self.D["show_fps"]:
            frame = self.show_chinese(frame,"fps: {:.2f}".format(1/(time.time()-t1)),(img_width-150,30),(255,0,0))
        self.show_result(frame)
        return frame, (N, X, Y, Z, L), coordinates, items

    # 单目批量检测
    def monocularBatch(self):
        files = os.listdir(self.D["source"])
        self.progressbar.setRange(0, len(files))
        num_value = 0
        self.singal.connect(self.update_progressbar)
        self.results_list = []
        for file in files:
            path = self.D["source"]
            self.event.wait()
            if self.run == False: break
            if file.endswith((".jpg",".png",".bmp")):
                path = path + "/" + file
                image = cv2.imread(path, 1)

                qt_image = QPixmap.fromImage(self.mat_to_qimage(image))
                item = QListWidgetItem(QIcon(qt_image), file)
                self.batch_listWidget.addItem(item)

                frame, re1, re2, items = self.monocularPredict(image)

                self.results_list.append([frame, re1, items])

                num_value += 1
                self.singal.emit(num_value)
                if self.D["save"]:
                    cv2.imwrite(self.D["save_path"]+"/"+file, frame)

    # 单目视频预测
    def monocularVidoe(self):
        video_path = self.D["source"]
        out = None
        if self.D["save"]:
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(self.D["save_path"]+"/"+os.path.basename(self.D["source"]), fourcc, 20.0, (1280, 720))

        video = cv2.VideoCapture(video_path)
        framse = video.get(cv2.CAP_PROP_FRAME_COUNT)

        self.progressbar.setRange(0, int(framse))
        num_value = 0
        self.singal.connect(self.update_progressbar)
        while video.isOpened() and self.run:
            self.event.wait()
            success, frame = video.read()
            if success:
                frame, re1, re2, items = self.monocularPredict(frame)
                if self.D["save"]:
                    out.write(cv2.resize(frame,(1280, 720)))
                num_value += 1
                self.singal.emit(num_value)
        video.release()
        if self.D["save"]: out.release()

    # 单目实时检测
    def monocularRealtime(self):
        capture = cv2.VideoCapture(int(self.D["source"]))  # 0为电脑内置摄像头
        out = None
        if self.D["save"]:
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(self.D["save_path"] + "/" + "output.mp4", fourcc, 20.0, (1280, 720))
        while (True):
            self.event.wait()
            if self.run == False: break
            ret, frame = capture.read()  # 摄像头读取,ret为是否成功打开摄像头,true,false。 frame为视频的每一帧图像
            frame = cv2.flip(frame, 1)  # 摄像头是和人对立的，将图像左右调换回来正常显示。
            frame, re1, re2, items = self.monocularPredict(frame)
            if self.D["save"]: out.write(cv2.resize(frame,(1280, 720)))
        capture.release()
        if self.D["save"]: out.release()

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    # 双目图片检测
    def binocularPredict(self, image_l=None, image_r=None):
        t1 = time.time()
        fxl, fyl = self.D["lfx"], self.D["lfy"]
        u0l, v0l = self.D["lu0"], self.D["lv0"]
        fxr, fyr = self.D["rfx"], self.D["rfy"]
        u0r, v0r = self.D["ru0"], self.D["rv0"]
        coordinates, items = list(), list()
        N, X, Y, Z, L = [], [], [], [], []
        self.target_listWidget.clear()
        self.target_list = []
        try:
            results_left, images_left = self.detect(image_l)
            results_right, images_right = self.detect(image_r)
            image_left, image_right = images_left[0], images_right[0]
            result_left, result_right = results_left[0], results_right[0]
            left_length, right_length = len(result_left.boxes.data), len(result_right.boxes.data)
            for l in range(left_length):
                l_id = int(result_left.boxes.data[l][5])
                lx = float(result_left.boxes.data[l][0])
                ly = float(result_left.boxes.data[l][1])
                lw = float(result_left.boxes.data[l][2])
                lh = float(result_left.boxes.data[l][3])
                lhight, lwidth = lh - ly , lw - lx
                for r in range(right_length):
                    r_id = int(result_right.boxes.data[r][5])
                    rx = float(result_right.boxes.data[r][0])
                    ry = float(result_right.boxes.data[r][1])
                    rw = float(result_right.boxes.data[r][2])
                    rh = float(result_right.boxes.data[r][3])
                    rhight, rwidth = rh - ry, rw - rx

                    if l_id != r_id or abs(result_left.boxes.data[l][4]-result_right.boxes.data[r][4])>1:
                        continue
                    if abs(lhight-rhight)>10 or abs(lwidth-rwidth)>10 or abs(ly-ry)>10 or abs(lh-rh)>10:
                        continue
                    Nc = result_left.names[l_id]
                    x1, x2 = (lx + lw) / 2, (rx + rw) / 2
                    y1, y2 = (ly + lh) / 2, (ry + rh) / 2
                    d = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** (0.5)
                    Zc = (fxl * self.D["spaceBetween"]) / d
                    Xc = -(((Zc * (x1 - u0l)) / fxl) + ((Zc * (x2 - u0r)) / fxr))
                    Yc = -(((Zc * (y1 - v0l)) / fyl) + ((Zc * (y2 - v0r)) / fyr))
                    Lc = (Xc ** 2 + Yc ** 2 + Zc ** 2) ** 0.5
                    if self.D["show_coordinate"]:
                        image_left = self.show_chinese(image_left, "x:{:.2f}cm\ny:{:.2f}cm\nz:{:.2f}cm".format(Xc,Yc,Zc),(lw+5, ly-10),(255, 250, 0))
                        image_right = self.show_chinese(image_right,"x:{:.2f}cm\ny:{:.2f}cm\nz:{:.2f}cm".format(Xc,Yc,Zc),(rw+5, ry-10),(255, 250, 0))

                    target_image = image_l[int(ly):int(lh), int(lx):int(lw)]
                    qt_image = QPixmap.fromImage(self.mat_to_qimage(target_image))
                    item = QListWidgetItem(QIcon(qt_image), Nc+"_l")
                    self.target_listWidget.addItem(item)
                    self.target_list.append([target_image, Nc, Xc, Yc, Zc, Lc])
                    items.append(target_image)
                    N.append(Nc)
                    X.append(Xc)
                    Y.append(Yc)
                    Z.append(Zc)
                    L.append(Lc)
                    coordinates.append((Nc, Xc, Yc, Zc))
                    result_right.boxes.data.remove(result_right.boxes.data[r])
                    break
        except:
            image_left, image_right = image_l, image_r
        self.plot_3D(N, Z, X, Y)
        self.N, self.X, self.Y, self.Z = N, X, Y, Z

        ck = self.layout.checkedButton().text()
        if ck == "左":
            newImage = image_left
        elif ck == "右":
            newImage = image_right
        else:
            height, width, channels = image_left.shape
            image_right = cv2.resize(image_right, (width, height))
            newImage = np.zeros((height, width * 2, channels), dtype=np.uint8)
            newImage[:height, :width] = image_left
            newImage[:height, width:] = image_right

        height, width, channels = newImage.shape
        if self.D["show_fps"]:
            newImage = self.show_chinese(newImage, "fps: {:.2f}".format(1/(time.time()-t1)), (width-200, 30),(255,0,0))
        self.show_result(newImage)
        return newImage, (N, X, Y, Z, L), coordinates, items

    # 双目批量检测
    def binocularBatch(self):
        if self.D["leftView"] == self.D["rightView"]: same = True
        else: same = False
        num_value = 0
        files_left,files_right = os.listdir(self.D["leftView"]),os.listdir(self.D["rightView"])
        self.progressbar.setRange(0, len(files_left))
        self.singal.connect(self.update_progressbar)
        t = dict(zip(files_left, files_right))

        self.results_list = []
        for file_left,file_right in t.items():
            self.event.wait()
            if self.run==False: break
            if file_left.endswith((".jpg",".png",".bmp")) and file_right.endswith((".jpg",".png",".bmp")):
                if same:
                    newImage  = cv2.imread(self.D["leftView"]+"/"+file_left)
                    h, w, _ = newImage.shape
                    wf = w // 2
                    image_l = newImage[0:h, 0:wf]
                    image_r = newImage[0:h, wf:w]
                else:
                    image_l = cv2.imread(self.D["leftView"]+"/"+file_left, 1)
                    image_r = cv2.imread(self.D["rightView"]+"/"+file_right, 1)

                qt_image_l = QPixmap.fromImage(self.mat_to_qimage(image_l))
                qt_image_r = QPixmap.fromImage(self.mat_to_qimage(image_r))
                item_l = QListWidgetItem(QIcon(qt_image_l), file_left)
                item_r = QListWidgetItem(QIcon(qt_image_r), file_right)
                self.batch_listWidget.addItem(item_l)
                self.batch_listWidget.addItem(item_r)
                frame, re1, re2, items = self.binocularPredict(image_l, image_r)

                self.results_list.append([frame, re1, items])
                self.results_list.append([frame, re1, items])
                num_value += 1
                self.singal.emit(num_value)
                if self.D["save"]:
                    cv2.imwrite(self.D["save_path"]+"/"+file_left, frame)
        self.singal.emit(len(files_left))

    # 双目视频检测
    def binocularVidoe(self):
        if self.D["leftView"]==self.D["rightView"]: same = True
        else: same = False
        out = None
        if self.D["save"]:
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(self.D["save_path"] + "/" + os.path.basename(self.D["leftView"]), fourcc, 20.0, (1280, 720))

        video_path_left, video_path_right = self.D["leftView"], self.D["rightView"]
        videol, videor = cv2.VideoCapture(video_path_left), cv2.VideoCapture(video_path_right)

        framse = videol.get(cv2.CAP_PROP_FRAME_COUNT)
        self.progressbar.setRange(0, int(framse))
        num_value = 0
        self.singal.connect(self.update_progressbar)
        while videol.isOpened() and videor.isOpened() and self.run:
            self.event.wait()
            successl, framel = videol.read()
            successr, framer = videor.read()
            if successl and successr:
                if same:
                    image = framel
                    h, w, _ = image.shape
                    wf = w // 2
                    image_l = image[0:h, 0:wf]
                    image_r = image[0:h, wf:w]
                else:
                    image_l, image_r = framel, framer
                frame, re1, re2, items = self.binocularPredict(image_l, image_r)
                num_value += 1
                self.singal.emit(num_value)
                if self.D["save"]:
                    out.write(cv2.resize(frame, (1280, 720)))
        videol.release()
        videor.release()
        if self.D["save"]: out.release()

    # 双目实时检测
    def binocularRealtime(self):
        out = None
        if self.D["save"]:
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(self.D["save_path"] + "/" + "output.mp4", fourcc, 20.0, (1280, 720))

        if self.D["rightView"] == self.D["leftView"]:
            cap = cv2.VideoCapture(int(self.D["leftView"]))
            cap.set(cv2.CAP_PROP_FRAME_WIDTH, 2560)
            cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
            while self.run:
                ret, frame = cap.read()
                self.event.wait()
                left_frame = frame[0:720, 0:1280]
                right_frame = frame[0:720, 1280:2560]
                frame, re1, re2, items = self.binocularPredict(image_l=left_frame, image_r=right_frame)
                if self.D["save"]:
                    out.write(cv2.resize(frame, (1280, 720)))
            cap.release()
        else:
            cap_l = cv2.VideoCapture(int(self.D["leftView"]))
            cap_r = cv2.VideoCapture(int(self.D["rightView"]))
            while self.run:
                self.event.wait()
                ret, image_l = cap_l.read()
                ret, image_r = cap_r.read()
                frame, re1, re2, items = self.binocularPredict(image_l, image_r)
                if self.D["save"]:
                    out.write(cv2.resize(frame, (1280, 720)))
                cap_l.release()
                cap_r.release()
        if self.D["save"]: out.release()

if __name__=='__main__':
    QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
    app = QApplication([])
    mypredict = myPredict()
    mypredict.mainWindow.show()
    # mypredict.showWindow.show()
    app.exec_()
    sys.exit()
